﻿using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Markup;
using XAMLStylePad.ViewModels;
using System.Windows.Documents;
using System.Windows.Threading;
using FireFly;

namespace XAMLStylePad.Views
{
    /// <summary>
    /// Interaction logic for PreviewPanel.xaml
    /// </summary>
    public partial class PreviewPanel : UserControl
    {
        public PreviewPanel()
        {
            InitializeComponent();
        }

        #region Control
        public FrameworkElement Control
        {
            get
            {
                return _Control;
            }
            set
            {
                _Control = value;
            }
        }
        FrameworkElement _Control;
        #endregion

        /// <summary>
        /// Removes old control from preview
        /// </summary>
        void RemoveOldControl()
        {
            if(Control is Window)
            {
                ((Window)Control).Close();
            }
            Control = null;
        
            ctrlPlacement.Children.Clear();
            _template = null;
            linkCreateNewDataObject.Visibility = Visibility.Collapsed;
        }


        /// <summary>
        /// Adds control to preview panel and set is as source for properties grid
        /// </summary>
        void SetControl(FrameworkElement control)
        {
            Control = control;
            if(Control != null && ctrlPlacement.Children.Count==0)
            {
                ctrlPlacement.Children.Add(Control);

                var element = Control as FrameworkElement;
                if(element != null && element.DataContext != null)
                {
                    previewProps.Instance = element.DataContext;
                }
                else
                    previewProps.Instance = Control;
            }
        }

        /// <summary>
        /// If passed control is FrameworkContentElement, this function will create sample control for preview it
        /// </summary>
        public static FrameworkElement GetControlForFrameworkContentElement(DependencyObject ctrl)
        {
            FrameworkElement control = null;

            if(!(ctrl is FrameworkContentElement))
                return control;
            else if(ctrl is TextElement)
            {
                FlowDocument doc;
                if(ctrl is Block)
                    doc = new FlowDocument(ctrl as Block);
                else
                    doc = new FlowDocument(new Paragraph(ctrl as Inline));

                control = new FlowDocumentReader()
                {
                    Document = doc
                };
            }
            else if(ctrl is FlowDocument)
            {
                control = new FlowDocumentReader()
                {
                    Document = ctrl as FlowDocument
                };
            }
            else if(ctrl is FixedDocument || ctrl is FixedDocumentSequence)
            { // FlowDocument, FixedDocument and FixedDocumentSequence
                control = new DocumentViewer()
                {
                    Document = ctrl as IDocumentPaginatorSource
                };
            }
            else if(ctrl is DefinitionBase)
            {
                var grid = new Grid();
                TextBlock txBlock = new TextBlock();
                control = grid;

                if(ctrl is RowDefinition)
                {
                    grid.RowDefinitions.Add(ctrl as RowDefinition);
                    txBlock.Text = "Sample RowDefinition";
                }
                else if(ctrl is ColumnDefinition)
                {
                    grid.ColumnDefinitions.Add(ctrl as ColumnDefinition);
                    txBlock.Text = "Sample ColumnDefinition";
                }
            }
            else if(ctrl is TableColumn)
            {
                var table = new Table();
                table.RowGroups.Add(new TableRowGroup());
                var row = new TableRow();
                table.RowGroups[0].Rows.Add(row);
                row.Cells.Add(new TableCell(new Paragraph(new Run("TableColumn sample"))));

                control = new FlowDocumentReader()
                {
                    Document = new FlowDocument(table)
                };
            }

            return control;
        }

        
        /// <summary>
        /// Make preview for style
        /// </summary>
        public void SetStyle(Style style)
        {
            if(style.TargetType != null)
            {
                try
                {
                    RemoveOldControl();
                    var ctrl = (DependencyObject)XamlSPViewModelService.CreateInstance(style.TargetType);

                    if(ctrl == null)
                    {
                        PreviewErrorMessage("Can't render sample conrol.\nSeams like type " + style.TargetType.FullName + " or its derived children\n doesn't have parameterless constructor");
                        return;
                    }

                    var addChildCtrl = ctrl as IAddChild;
                    if(addChildCtrl != null)
                    {
                        if(ctrl is ItemsControl)
                        {
                            addChildCtrl.AddChild("Item 1");
                            addChildCtrl.AddChild("Item 2");
                        }
                        else if(ctrl is Decorator || ctrl is Panel)
                        {
                            addChildCtrl.AddChild(new TextBlock()
                            {
                                Text = "Sample " + ctrl.GetType().Name
                            });
                        }
                        else if(ctrl is Window)
                        {//window can't be added like child in visual tree.
                            var wnd = ctrl as Window;
                            Control = wnd;
                            Dispatcher.BeginInvoke((Action)delegate
                            {
                                wnd.Show();
                            }, DispatcherPriority.Background, null);
                            return;
                        }
                        else if(ctrl is ContentControl)
                        {
                            ((ContentControl)addChildCtrl).Content = new TextBlock()
                            {
                                Text = "Sample " + ctrl.GetType().Name
                            };
                        }
                        else if(!(ctrl is RichTextBox))
                        {
                            addChildCtrl.AddText("Sample " + ctrl.GetType().Name);
                        }
                    }

                    SetControl(GetControlForFrameworkContentElement(ctrl) ?? addChildCtrl as FrameworkElement);

                    if(ctrl is FrameworkElement)
                    {
                        var frameworkCtrl = ctrl as FrameworkElement;
                        frameworkCtrl.Style = style;
                    }
                    else if(ctrl is FrameworkContentElement)
                    {
                        ((FrameworkContentElement)ctrl).Style = style;
                    }
                }
                catch(Exception err)
                {
                    PreviewErrorMessage(err);
                }
            }
        }

        /// <summary>
        /// Make preview for template
        /// </summary>
        public void SetTemplate(TemplateViewModel template)
        {
            try
            {
                RemoveOldControl();
                _template = template;
                linkCreateNewDataObject.Visibility = Visibility.Visible;
                SetControl((FrameworkElement)ObjectProvider.GetTemplatesControl(template, false));
                
            }
            catch(Exception err)
            {
                PreviewErrorMessage(err);
            }
        }
        TemplateViewModel _template;

        ///// <summary>
        ///// Creates templated control witj
        ///// </summary>
        ///// <param name="data"></param>
        //public void SetDataObjectForTemplate(object data)
        //{
        //    try
        //    {
        //        var template = _template;
        //        var ctrl = template.LoadContent() as FrameworkElement;
        //        RemoveOldControl(); // clears current _template value
        //        Control = ctrl;
        //        ctrl.DataContext = data;
        //        ShowControl();
        //        _template = template;
        //    }
        //    catch(Exception err)
        //    {
        //        ViewModelService.Instance.ShowErrorMessage(err);
        //    }
        //}

        public void ResetObject()
        {
            RemoveOldControl();
            Control = null;
        }

        public void SetElement(FrameworkElement element)
        {
            RemoveOldControl();
            SetControl(element);
        }

        public void PreviewErrorMessage(Exception err)
        {
            this.PreviewErrorMessage(err.Message + "\n\n" + err.StackTrace);
        }

        void PreviewErrorMessage(string msg)
        {
            RemoveOldControl();
            Control = new TextBlock()
            {
                Text = msg
            };
            ctrlPlacement.Children.Add((FrameworkElement)Control);
        }

        private void Hyperlink_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                var tmp = _template;
                ResetObject(); // clear _template value
                _template = tmp;
                _template.Data = null;
                linkCreateNewDataObject.Visibility = Visibility.Visible;

                SetControl((FrameworkElement)ObjectProvider.GetTemplatesControl(_template, true));
            }
            catch(Exception err)
            {
                PreviewErrorMessage(err);
            }
        }
    }
}
